package com.weilx959.spt.core.component;

import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.sun.javafx.tk.Toolkit;
import com.weilx959.spt.core.LanguageContext;
import com.weilx959.spt.core.RootPaneContext;
import com.weilx959.spt.core.constants.CommonConstants;
import com.weilx959.spt.core.constants.LanguageEnum;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * VDialog
 * 弹窗组件
 *
 * @author weilx
 * @since 2024年6月12日
 */
@Slf4j
public class VDialog {
    private VDialog() {
    }

    public static void alert(String message) {
        createDialog(message, DialogType.ALERT, VDialog::close,  VDialog::close)
            .show(RootPaneContext.get());
    }

    public static void alert(String message, Consumer<JFXDialog> okAction) {
        createDialog(message, DialogType.ALERT, okAction,  VDialog::close)
            .show(RootPaneContext.get());
    }

    public static <T> T alertBlocked(String message) {
        JFXDialog dialog = VDialog.<T>createDialog(message, DialogType.ALERT,  VDialog::close,  VDialog::close);
        dialog.show(RootPaneContext.get());
        dialog.setOnDialogClosed(event -> Toolkit.getToolkit().exitNestedEventLoop(dialog, null));
        Toolkit.getToolkit().enterNestedEventLoop(dialog);
        return ((ObjectProperty<T>)dialog.getUserData()).get();
    }

    public static <T> T alertBlocked(String message, Function<JFXDialog, T> okAction) {
        JFXDialog dialog = createBlockedDialog(message, DialogType.ALERT, okAction,  VDialog::close);
        dialog.show(RootPaneContext.get());
        dialog.setOnDialogClosed(event -> Toolkit.getToolkit().exitNestedEventLoop(dialog, null));
        Toolkit.getToolkit().enterNestedEventLoop(dialog);
        return ((ObjectProperty<T>)dialog.getUserData()).get();
    }

    public static void confirm(String message, Consumer<JFXDialog> okAction) {
        createDialog(message, DialogType.CONFIRM, okAction, VDialog::close)
            .show(RootPaneContext.get());
    }

    public static void confirm(String message, Consumer<JFXDialog> okAction, Consumer<JFXDialog> cancelAction) {
        createDialog(message, DialogType.CONFIRM, okAction, cancelAction)
            .show(RootPaneContext.get());
    }

    public static <T> T confirmBlocked(String message, Function<JFXDialog, T> okAction) {
        JFXDialog dialog = createBlockedDialog(message, DialogType.CONFIRM, okAction,  VDialog::close);
        dialog.show(RootPaneContext.get());
        dialog.setOnDialogClosed(event -> Toolkit.getToolkit().exitNestedEventLoop(dialog, null));
        Toolkit.getToolkit().enterNestedEventLoop(dialog);
        return ((ObjectProperty<T>)dialog.getUserData()).get();
    }

    public static <T> T confirmBlocked(String message, Function<JFXDialog, T> okAction, Function<JFXDialog, T> cancelAction) {
        JFXDialog dialog = createBlockedDialog(message, DialogType.CONFIRM, okAction, cancelAction);
        dialog.show(RootPaneContext.get());
        dialog.setOnDialogClosed(event -> Toolkit.getToolkit().exitNestedEventLoop(dialog, null));
        Toolkit.getToolkit().enterNestedEventLoop(dialog);
        return ((ObjectProperty<T>)dialog.getUserData()).get();
    }

    private static JFXDialog createDialog(String message, DialogType type,
                                              Consumer<JFXDialog> okAction, Consumer<JFXDialog> cancelAction) {
        JFXDialog dialog = new JFXDialog();
        dialog.setOverlayClose(false);

        Label text = new Label(message);
        text.getStyleClass().add("v-dialog-text");

        HBox buttonBox = new HBox(10);
        buttonBox.getStyleClass().add("v-dialog-button-box");
        buttonBox.getChildren().addAll(createButtons(type, event -> {
            event.consume();
            if (Objects.nonNull(okAction)) {
                okAction.accept(dialog);
            }
        }, event -> {
            event.consume();
            if (Objects.nonNull(cancelAction)) {
                cancelAction.accept(dialog);
            }
        }));

        VBox content = new VBox(2, text, buttonBox);
        content.getStyleClass().add("v-dialog-content");
        VBox.setVgrow(text, Priority.ALWAYS);
        VBox.setVgrow(buttonBox, Priority.NEVER);

        dialog.setContent(content);
        return dialog;
    }

    private static <T> JFXDialog createBlockedDialog(String message, DialogType type,
                                          Function<JFXDialog, T> okAction, Function<JFXDialog, T> cancelAction) {
        JFXDialog dialog = new JFXDialog();
        dialog.setOverlayClose(false);
        dialog.setUserData(new SimpleObjectProperty<T>());

        Label text = new Label(message);
        text.getStyleClass().add("v-dialog-text");

        HBox buttonBox = new HBox(10);
        buttonBox.getStyleClass().add("v-dialog-button-box");
        buttonBox.getChildren().addAll(createButtons(type, event -> {
            event.consume();
            if (Objects.nonNull(okAction)) {
                ((ObjectProperty<T>)dialog.getUserData()).set(okAction.apply(dialog));
            }
        }, event -> {
            event.consume();
            if (Objects.nonNull(cancelAction)) {
                ((ObjectProperty<T>)dialog.getUserData()).set(cancelAction.apply(dialog));
            }
        }));

        VBox content = new VBox(2, text, buttonBox);
        content.getStyleClass().add("v-dialog-content");
        VBox.setVgrow(text, Priority.ALWAYS);
        VBox.setVgrow(buttonBox, Priority.NEVER);

        dialog.setContent(content);
        return dialog;
    }

    private static List<JFXButton> createButtons(DialogType type, EventHandler<ActionEvent> okAction, EventHandler<ActionEvent> cancelAction) {
        Locale locale = Optional.ofNullable(LanguageContext.get()).map(LanguageEnum::getLocale).orElse(CommonConstants.DEFAULT_LANGUAGE.getLocale());
        ResourceBundle bundle = ResourceBundle.getBundle(CommonConstants.CORE_BASE_NAME, locale);
        return switch (type) {
            case ALERT -> {
                JFXButton ok = new JFXButton(bundle.getString("core.dialog.ok"));
                ok.getStyleClass().add("ok-button");
                ok.setOnAction(okAction);
                yield List.of(ok);
            }
            case CONFIRM -> {
                JFXButton ok = new JFXButton(bundle.getString("core.dialog.ok"));
                ok.getStyleClass().add("ok-button");
                ok.setOnAction(okAction);
                JFXButton cancel = new JFXButton(bundle.getString("core.dialog.cancel"));
                cancel.getStyleClass().add("cancel-button");
                cancel.setOnAction(cancelAction);
                yield List.of(cancel, ok);
            }
        };
    }
    
    public static <T> T close(JFXDialog dialog) {
        dialog.close();
        return null;
    }

    public enum DialogType {
        ALERT,
        CONFIRM
    }
}
